## Supporting functions:

# Function to input attributes into new network:
input_attr_network <- function(some_network, some_attr) {
  # some_network = list_networks_weak[[2]]
  # some_attr = "male_imputed"
  id_to_match <- as.numeric(network.vertex.names(some_network))
  
  to_replace <- rep(NA, length(id_to_match))
  
  for (j in 1:length(id_to_match)) {
    #j = 1
    to_replace[j] <- data[as.numeric(id_to_match[j]), get(some_attr)]
  }
  
  some_network %v% some_attr <- to_replace
  return(some_network)
}  

# Create function to compute popularity index for all races: -----
popularity_index <- function(some_network) {
  # some_network = list_networks_strong[[3]]
  
  # Get the components of each graph:
  cd <- component.dist(some_network, 
                       connected="strong")   # Run components algorithm for "weak" components
  some_network %v% "component" <- cd$membership   # Add "component" to vertex attributes
  
  list_components <- list()
  for (i in 1:length(unique(cd$membership))) {
    list_components[[i]] <- get.inducedSubgraph(some_network,v=which(some_network %v% "component"== i ))
  }
  
  ##### Get eigenvalue of the matrix:
  
  e <- lapply(list_components, function(k) eigen(as.sociomatrix.sna(k)))
  
  names <- sapply(list_components, network.vertex.names)
  names <- as.numeric(as.vector(unlist(names)))
  
  cssi <- sapply(e, function(x) max(as.double(x$values)) )
  ev <- lapply(e, function(x) as.double(x$vectors[, which.max(as.double(x$values))] ))
  
  issi <- unlist( lapply( seq(1, length(e)),
                          function(i)
                          {
                            rval <- cssi[i] * ev[[i]] / mean(ev[[i]])
                            names(rval) <- network.vertex.names(list_components[[i]])
                            rval
                          } ) )
  
  nome_ssi <- cbind(names, issi)

  return(nome_ssi)    
}

# Standardize variables:
std_vector <- function(some_vector) {
  (some_vector - mean(some_vector[selection_criteria], na.rm = T))/sd(some_vector[selection_criteria], na.rm = T)
}

# Compute number of friends and other measures of centrality
Eigen <- function(some_network) {
  eig_cent <- round(sna::evcent(some_network), 5)  
  names <- as.numeric(network.vertex.names(some_network))
  
  some_network %v% "eigen_cent" <- eig_cent
  
  return(cbind(names, eig_cent))
}

Indegree <- function(some_network) {
  in_degree <- round(sna::degree(some_network, cmode="indegree"), 5)  
  names <- as.numeric(network.vertex.names(some_network))
  
  some_network %v% "in_degree" <- in_degree
  
  return(cbind(names, in_degree))
  
}

Outdegree <- function(some_network) {
  out_degree <- round(sna::degree(some_network, cmode="outdegree"), 5)  
  names <- as.numeric(network.vertex.names(some_network))
  
  some_network %v% "out_degree" <- out_degree
  
  return(cbind(names, out_degree))
  
}

# Create the variables to receive the number of friends of each color:
get_friends <- function(some_network) {

  class_size <- network::network.size(some_network)
  
  fill_in_friends <- matrix(NA, nrow = class_size, ncol = 11)
  
  for (i in 1:class_size) {
    # i = 1
    myneigh <- network::get.neighborhood(some_network, v = i)
    myid    <- as.numeric(network::network.vertex.names(some_network)[i])
    myrace  <- network::get.vertex.attribute(some_network, attrname = "race_simple")[i]
    myrace_nw  <- network::get.vertex.attribute(some_network, attrname = "negro_na")[i]
    my_friends_race <- network::get.vertex.attribute(some_network, attrname = "race_simple")[myneigh]
    my_friends_race_nw <- network::get.vertex.attribute(some_network, attrname = "negro_na")[myneigh]
    my_friends <- length(myneigh)
    my_white_friends <- length(which(my_friends_race == 1))
    my_black_friends <- length(which(my_friends_race == 2))
    my_brown_friends <- length(which(my_friends_race == 3))
    my_other_friends <- length(which(my_friends_race == 4))
    my_same_race_friends <- length(which(my_friends_race == myrace))
    my_same_race_nw_friends <- length(which(my_friends_race_nw == myrace_nw))
    my_nonwhite_friends <- my_brown_friends + my_black_friends # Only black and browns
    
    if (is.na(myrace) == T) {
      diff_fr <- NA
      diff_nw_fr <- NA
    } else if (myrace == 1) {
      diff_fr <- my_black_friends + my_brown_friends + my_other_friends
      diff_nw_fr <- my_black_friends + my_brown_friends 
    } else if (myrace == 2) {
      diff_fr <- my_white_friends + my_brown_friends + my_other_friends
      diff_nw_fr <- my_white_friends 
      
    } else if (myrace == 3) {
      diff_fr <- my_white_friends + my_black_friends + my_other_friends
      diff_nw_fr <- my_white_friends 
      
    } else if (myrace == 4) {
      diff_fr <- my_black_friends + my_brown_friends + my_white_friends
      diff_nw_fr <- NA
    } 
    
    fill_in_friends[i,1] <- myid
    fill_in_friends[i,2] <- my_friends
    fill_in_friends[i,3] <- my_white_friends
    fill_in_friends[i,4] <- my_black_friends
    fill_in_friends[i,5] <- my_brown_friends
    fill_in_friends[i,6] <- my_other_friends
    fill_in_friends[i,7] <- my_nonwhite_friends
    fill_in_friends[i,8] <- diff_fr
    fill_in_friends[i,9] <- diff_nw_fr
    fill_in_friends[i,10] <- my_same_race_friends
    fill_in_friends[i,11] <- my_same_race_nw_friends
  }
  some_network %v% "friends" <- fill_in_friends[,2]
  some_network %v% "white_friends" <- fill_in_friends[,3]
  some_network %v% "black_friends" <- fill_in_friends[,4]
  some_network %v% "brown_friends" <- fill_in_friends[,5]
  some_network %v% "other_friends" <- fill_in_friends[,6]
  some_network %v% "nonwhite_friends" <- fill_in_friends[,7]
  some_network %v% "diff_friends" <- fill_in_friends[,8]
  some_network %v% "diff_nw_friends" <- fill_in_friends[,9]
  some_network %v% "my_same_race_friends" <- fill_in_friends[,10]
  some_network %v% "my_same_race_nw_friends" <- fill_in_friends[,11]
  
  return_list <- list(some_network, fill_in_friends)
  return(return_list)
}  

ssib_net <- function(g, vattr, b)  {
  
  ids <- network::get.vertex.attribute(g, vattr)
  if (is.na(b) == T) {
    sub <- get.inducedSubgraph(g,v=which(is.na(g %v% vattr) == T ))
  } else {
    sub <- get.inducedSubgraph(g,v=which(g %v% vattr == b ))  
  }
  
  
  # Get connected component of each racial subnetwork:
  cd<-component.dist(sub, 
                     connected="strong")   # Run components algorithm for "strong" components
  sub %v% "component" <- cd$membership   # Add "component" to vertex attributes
  
  list_components <- list()
  for (j in 1:length(unique(cd$membership))) {
    list_components[[j]] <- network::get.inducedSubgraph(sub,v=which(sub %v% "component"== j ))
  }
  
  # Compute eigenvalue decomposition to each component:
  e <- lapply(list_components, function(k) eigen(as.sociomatrix.sna(k)))
  
  names <- sapply(list_components, network::network.vertex.names)
  names <- as.numeric(as.vector(unlist(names)))
  
  cssi <- sapply(e, function(x) max(as.double(x$values)) )
  ev <- lapply(e, function(x) as.double(x$vectors[, which.max(as.double(x$values))] ))
  
  issi <- unlist( lapply( seq(1, length(e)),
                          function(i)
                          {
                            rval <- cssi[i] * ev[[i]] / mean(ev[[i]])
                            names(rval) <- network::network.vertex.names(list_components[[i]])
                            rval
                          } ) )
  issi = issi[ order(as.numeric(names(issi))) ]
  
}

ssi_net <- function(g, vattr) {
  gg <-  network(network::as.matrix.network.adjacency(g) , directed = T)
  gg %v% vattr <- network::get.vertex.attribute(g, vattr)
  degs <- sna::degree(gg, cmode = "outdegree")
  
  a <- network::get.vertex.attribute(gg, vattr)
  l <- unlist(lapply(unique(a), 
                     function(val) ssib_net(g = gg, vattr = vattr, b = val)))
  
  l[ order(as.numeric(names(l)))]
}

ssi_net_other_2_race <- function(g, vattr) {

  print(unique(network::get.vertex.attribute(g, "school_id")))
  print(unique(network::get.vertex.attribute(g, "class_id")))
  
  gg <-  network(network::as.matrix.network.adjacency(g) , directed = T)
  gg %v% vattr <- network::get.vertex.attribute(g, vattr)
  degs <- sna::degree(gg, cmode = "outdegree")
  
  a <- network::get.vertex.attribute(gg, vattr)
  ssi_other <- rep(NA, network.size(gg))
  names(ssi_other) <- network.vertex.names(gg)
  
  original_ids <- get.vertex.attribute(gg,vattr)
  
  for (ind in 1:network.size(gg)) {
    # ind = 1
    set.vertex.attribute(gg,vattr, value = original_ids)
    ids <- get.vertex.attribute(gg,vattr)
    my_id <- network.vertex.names(gg)[ind]
    
    if (is.na(ids[ind]) == T) {
      print("Do nothing")
    } else if (ids[ind] == 1) {
      ids[ind] <- 0
    } else if (ids[ind] == 0) {
      ids[ind] <- 1
    }
    
    set.vertex.attribute(gg,vattr, value = ids)
    get.vertex.attribute(gg,vattr)
    size_problem <- length(get.vertex.attribute(gg,vattr))
    
    diversity <- length(table(get.vertex.attribute(gg,vattr)))
    if (diversity == 1) {
      ssi_other[ind] <- 0
    } else if (size_problem == 2) {
      ssi_other[ind] <- 0
    } else {
      l <- unlist(lapply(unique(a), 
                         function(val) ssib_net(g = gg, vattr = vattr, b = val)))
      
      l[ order(as.numeric(names(l)))]
      ssi_other[ind] <- l[which(names(l) == my_id)] 
    }
  }
  
  return(ssi_other)
}

ssi_net_other_3_race <- function(g, vattr) {
  # g = list_networks_strong[[3]]  
  # vattr = "race_simple"
  # ind = 1
  gg <-  network(network::as.matrix.network.adjacency(g) , directed = T)
  gg %v% vattr <- network::get.vertex.attribute(g, vattr)
  degs <- sna::degree(gg, cmode = "outdegree")
  
  a <- network::get.vertex.attribute(gg, vattr)
  ssi_other <- rep(NA, network.size(gg))
  names(ssi_other) <- network.vertex.names(gg)
  
  original_ids <- get.vertex.attribute(gg,vattr)
  
  for (ind in 1:network.size(gg)) {
    set.vertex.attribute(gg,vattr, value = original_ids)
    ids <- get.vertex.attribute(gg,vattr)
    my_id <- network.vertex.names(gg)[ind]
    
    if (is.na(ids[ind]) == T) {
      print("Do nothing")
    } else if (ids[ind] == 1) {
      
      ids[ind] <- 0
      ids[which(ids != 1 & is.na(ids) == F)]  <- 0
      
    } else if (ids[ind] == 2) {
      
      ids[ind] <- 0
      ids[which(ids != 2 & is.na(ids) == F)]  <- 0
    } else if (ids[ind] == 3) {
      
      ids[ind] <- 0
      ids[which(ids != 3 & is.na(ids) == F)] <- 0
      
    } else if (ids[ind] == 4) {
      
      ids[ind] <- 0
      ids[which(ids != 4 & is.na(ids) == F)] <- 0
      
    }  
    
    set.vertex.attribute(gg,vattr, value = ids)
    
    l <- unlist(lapply(unique(ids), 
                       function(val) ssib_net(g = gg, vattr = vattr, b = val)))
    
    l[ order(as.numeric(names(l)))]
    ssi_other[ind] <- l[which(names(l) == my_id)] 
  }
  set.vertex.attribute(gg,vattr, value = original_ids)
  return(ssi_other)
}
